"""
安全工具
提供密码哈希、加密和安全相关功能
"""
import os
import re
import bcrypt
import secrets
import hashlib
from functools import wraps
from flask import request, current_app
from werkzeug.security import safe_str_cmp


def hash_password(password):
    """
    对密码进行哈希处理
    
    参数:
        password: 明文密码
    
    返回:
        哈希后的密码
    """
    if isinstance(password, str):
        password = password.encode('utf-8')
    
    salt = bcrypt.gensalt()
    hashed = bcrypt.hashpw(password, salt)
    
    return hashed.decode('utf-8')


def check_password(password, hashed):
    """
    验证密码是否与哈希匹配
    
    参数:
        password: 明文密码
        hashed: 哈希密码
    
    返回:
        密码是否匹配
    """
    if isinstance(password, str):
        password = password.encode('utf-8')
    
    if isinstance(hashed, str):
        hashed = hashed.encode('utf-8')
    
    return bcrypt.checkpw(password, hashed)


def generate_secure_token(length=64):
    """
    生成安全随机令牌
    
    参数:
        length: 令牌长度
    
    返回:
        安全随机令牌
    """
    return secrets.token_hex(length // 2)


def generate_password_reset_token(user_id):
    """
    生成密码重置令牌
    
    参数:
        user_id: 用户ID
    
    返回:
        重置令牌
    """
    # 组合用户ID和当前时间与随机数据
    data = f"{user_id}-{secrets.token_hex(16)}-{int(time.time())}"
    
    # 使用应用密钥进行HMAC签名
    secret = current_app.config['SECRET_KEY'].encode('utf-8')
    signature = hmac.new(secret, data.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()
    
    # 组合数据和签名
    token = f"{data}.{signature}"
    
    # Base64编码使其URL安全
    return base64.urlsafe_b64encode(token.encode('utf-8')).decode('utf-8')


def verify_password_reset_token(token, expiration=86400):
    """
    验证密码重置令牌
    
    参数:
        token: 重置令牌
        expiration: 过期时间（秒）
    
    返回:
        用户ID或None（如果令牌无效）
    """
    try:
        # 解码令牌
        token = base64.urlsafe_b64decode(token).decode('utf-8')
        
        # 分离数据和签名
        data, signature = token.rsplit('.', 1)
        
        # 验证签名
        secret = current_app.config['SECRET_KEY'].encode('utf-8')
        expected_signature = hmac.new(secret, data.encode('utf-8'), digestmod=hashlib.sha256).hexdigest()
        
        if not safe_str_cmp(signature, expected_signature):
            return None
        
        # 解析数据
        parts = data.split('-')
        if len(parts) != 3:
            return None
        
        user_id, _, timestamp = parts
        
        # 检查是否过期
        if int(time.time()) - int(timestamp) > expiration:
            return None
        
        return user_id
    
    except Exception as e:
        current_app.logger.error(f"验证密码重置令牌出错: {str(e)}")
        return None


def is_strong_password(password, min_length=8):
    """
    检查密码强度
    
    参数:
        password: 密码
        min_length: 最小长度
    
    返回:
        密码是否足够强
    """
    if len(password) < min_length:
        return False
    
    # 检查密码是否包含数字
    if not re.search(r"\d", password):
        return False
    
    # 检查密码是否包含小写字母
    if not re.search(r"[a-z]", password):
        return False
    
    # 检查密码是否包含大写字母
    if not re.search(r"[A-Z]", password):
        return False
    
    # 检查密码是否包含特殊字符
    if not re.search(r"[ !@#$%^&*()_+\-=\[\]{};':\"\\|,.<>\/?]", password):
        return False
    
    return True


def sanitize_html(html_content):
    """
    清理HTML内容中的危险标签和属性
    
    参数:
        html_content: HTML内容
    
    返回:
        清理后的HTML内容
    """
    # 实现简单的HTML清理
    # 注意：实际使用时应该使用专业库如bleach
    
    # 移除脚本标签
    html_content = re.sub(r'<script.*?>.*?</script>', '', html_content, flags=re.DOTALL)
    
    # 移除事件处理属性
    html_content = re.sub(r'on\w+=".*?"', '', html_content)
    html_content = re.sub(r"on\w+='.*?'", '', html_content)
    
    # 移除iframe标签
    html_content = re.sub(r'<iframe.*?>.*?</iframe>', '', html_content, flags=re.DOTALL)
    
    # 移除style属性
    html_content = re.sub(r'style=".*?"', '', html_content)
    html_content = re.sub(r"style='.*?'", '', html_content)
    
    return html_content


def require_api_key(f):
    """
    验证API密钥的装饰器
    
    参数:
        f: 被装饰的函数
    
    返回:
        装饰器函数
    """
    @wraps(f)
    def decorated(*args, **kwargs):
        api_key = request.headers.get('X-API-Key')
        
        if not api_key:
            return {
                'status': 'error',
                'message': '缺少API密钥'
            }, 401
        
        # 获取有效的API密钥列表
        valid_keys = current_app.config.get('API_KEYS', [])
        
        if api_key not in valid_keys:
            return {
                'status': 'error',
                'message': 'API密钥无效'
            }, 401
        
        return f(*args, **kwargs)
    
    return decorated 